iT邦幫忙

2024 iThome 鐵人賽

DAY 9
0

union 用來定義多型別單一值。

如有某一個數值在概念上可以用多種型別表達,但同時只會是一種型別的話,就可以用 union 處理。

基本

const std = @import("std");

const Result = union {
    int: u8,
    boolean: bool,
};

pub fn main() void {
    const res1 = Result{ .int = 32 };
    const res2 = Result{ .boolean = true };
    std.debug.print("Result: {}\n", .{res1.int});
    std.debug.print("Result: {}\n", .{res2.boolean});

    // Error
    // std.debug.print("Result: {}\n", .{res1.boolean});
    // std.debug.print("Result: {}\n", .{res2.int});
}
Result: 32
Result: true

Tagged

你可以爲 union 加上 enum 標記,這樣它會變成 Tagged union,隨後你可以使用其 enum 來判斷目前是那個型別在作用中。通常搭配 switch 和 Payload 語法使用。

const std = @import("std");

const ResultTag = enum { int, boolean };

const Result = union(ResultTag) {
    int: u8,
    boolean: bool,
};

pub fn main() void {
    const res1 = Result{ .int = 32 };
    switch (res1) {
        ResultTag.int => |value| std.debug.print("int: {}\n", .{value}),
        ResultTag.boolean => |value| std.debug.print("boolean: {}\n", .{value}),
    }

    const res2 = Result{ .boolean = false };
    switch (res2) {
        ResultTag.int => |value| std.debug.print("int: {}\n", .{value}),
        ResultTag.boolean => |value| std.debug.print("boolean: {}\n", .{value}),
    }
}
int: 32
boolean: false

如果覺得這樣還要多打一個 enum 很麻煩的話,可以直接在 union() 內鍵入 enum。注意 switch 配對的對象。

// 這裡和上面的程式效果一樣
const std = @import("std");

const Result = union(enum) {
    int: u8,
    boolean: bool,
};

pub fn main() void {
    const res1 = Result{ .int = 32 };
    switch (res1) {
        Result.int => |value| std.debug.print("int: {}\n", .{value}),
        Result.boolean => |value| std.debug.print("boolean: {}\n", .{value}),
    }

    const res2 = Result{ .boolean = false };
    switch (res2) {
        Result.int => |value| std.debug.print("int: {}\n", .{value}),
        Result.boolean => |value| std.debug.print("boolean: {}\n", .{value}),
    }
}

方法

如同 structenum,Zig 的 union 也可以包含方法。

const std = @import("std");

const Result = union(enum) {
    int: u8,
    boolean: bool,

    pub fn print(self: Result) void {
        switch (self) {
            Result.int => |value| std.debug.print("int: {}\n", .{value}),
            Result.boolean => |value| std.debug.print("boolean: {}\n", .{value}),
        }
    }
};

pub fn main() void {
    const res1 = Result{ .int = 32 };
    res1.print();

    const res2 = Result{ .boolean = true };
    res2.print();
}
int: 32
boolean: true

Tag Name

Tagged union 如果要取得字串形式的 tag name,可以用 @tegName

const std = @import("std");

const Result = union(enum) {
    int: u8,
    boolean: bool,
};

pub fn main() void {
    std.debug.print("Name: {s}\n", .{@tagName(Result.int)});
}
Name: int

參考

本文以 Zig 0.13.0 爲主。並同時發佈在:


上一篇
Zig:列舉(Enum)
下一篇
Zig:陣列(Array)和切片(Slices)
系列文
Zig 語言入門指南——聽説你是現代化的 C30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言